package com.sisyphe.android.srouter.internal

import android.app.Application
import android.content.Context
import com.sisyphe.android.srouter.exception.InitException
import com.sisyphe.android.srouter.facade.IProviderGroup
import com.sisyphe.android.srouter.facade.ProviderMeta
import dalvik.system.DexFile
import java.io.File

internal object _SRouter {

    private var hasInit = false

    private lateinit var mApplication: Context

    private val hashMap by lazy { mutableMapOf<String, ProviderMeta>() }

    internal fun init(application: Application) {
        hasInit = true
        mApplication = application

        val clazz = IProviderGroup::class.java

        getSourcePaths()
    }

    internal fun inject(that: Any) {
        if (!hasInit) {
            throw InitException("SRouterCore::Init::Invoke init(application) first!")
        }
        val clazz = that::class.java
        clazz.declaredFields.forEach { field ->
            val providerMate = hashMap[field.toString().split(' ')[1]]
            providerMate?.let { pm ->
                val destination = pm.destination
                val obj = destination.getDeclaredConstructor().newInstance()
                field.set(that, obj)
            }
        }
    }

    private fun getSourcePaths() {
        val codeApkPath = mApplication.packageCodePath
        val dexFiles = hashSetOf<DexFile>()
        val dir = File(codeApkPath).parentFile
        dir?.listFiles()?.forEach {
            val absolutePath = it.absolutePath
            if (absolutePath.contains(".")) {
                val suffix = absolutePath.substring(absolutePath.lastIndexOf("."))
                if (".apk" == suffix) {
                    val dexFile = DexFile(it.absolutePath)
                    dexFiles.add(dexFile)
                }
            }
        }

        val classList = arrayListOf<String>()
        dexFiles.forEach {
            val entries = it.entries()
            while (entries.hasMoreElements()) {
                val currentClassPath = entries.nextElement()
                if (currentClassPath.startsWith("com.sisyphe.android.srouter.collections.")) {
                    classList.add(currentClassPath)
                }
            }
        }

        val classLoader = Thread.currentThread().contextClassLoader

        classList.forEach {
            val entryClass = Class.forName(it, true, classLoader)
            val obj = entryClass.getDeclaredConstructor().newInstance()
            val method = entryClass.getDeclaredMethod("append", MutableMap::class.java)
            method.invoke(obj, hashMap)
        }
    }
}